AP计算机科学A复习:Unit 2 – Using Objects 面对对象编程

AP计算机科学A复习:Unit 2 – Using Objects 面对对象编程

Java是「面向对象编程」的语言。意思就是通过编程来实现对「对象」进行操作,这里所说的对象是「Objects」。我们会先了解什么是「Objects」,然后学习如何与「Objects」有关的编程语句。比如,如何新建一个Object并对它进行操作。

U2.1 Objects: Instances of Classes

所有的Objects, Methods等等元素必须依附于Class。在之前的程序写作中,这个特征具体的表现为我们要把Method写在某个Class的范围内。我们通过一个具象化的例子来理解这堆名词之间的关系。下图展示了一个简单的学生名单,每个学生拥有各种各样的信息,例如图中的学号、姓名、年龄、以及性别。每一项信息被称为「field」,蓝色高亮部分就是一个field的例子。一个拥有这些信息的学生就被称作一个「Object」,图中淡黄色高亮部分的学号为0003的这名学生就是一个例子。「Class」作为顶层的容器,把以上提到的所有元素容纳起来,是汇集具有相同特征的数据和功能的地方(图中粉色的高亮部分)。

Objects是Class的实例。可以把Class看作是Objects的蓝图或者模版。因此,我们创建一个Object的手段就是把Class实例化「Instantiation」,这样相当于从照着模版把下面的表格新增一行,然后我们就可以为一个新的「Object」填写他的信息。我们会在U2.2介绍如何在程序写作中实现「新建Object」。

「Method」则是对Object做出的动作,可以想象为图中深黄色高亮部分的三个蓝色按钮。比如,我们可以输出学生名单中的所有姓名,加上「交作业啦」的提示,这样就形成了一条提醒学生交作业的文本通知。当然这只是一种简单的例子,功能更完善的Method写作语法会在U2.3-U2.5中逐步介绍。

U2.2 Creating and Storing Objects (Instantiation)

「Constructor」是一种特别的Method,作用是给「Object」的各项信息赋初始值,它会在「Instantiation」语句运行时自动被调用。当我们调用一个Method时,程序会暂时脱离原来的顺序结构转而运行被调用的method的内容。等到被调用的method运行完后,再返回到原来的顺序结构中继续运行。比如下图中第四行的时候调用了一个method,因此程序会在第四行时跳转到下方void method 的部分。等到void method里面的程序语句被执行完后,才继续顺序执行上方第五行的语句。Constructor同理。

只是做逻辑展示,程序语句不是这么写的。后面讲具体的写法。

在Java程序写作中,如果说「Class」里的fields组成了表格的表头,「instantiation」的过程就是依据表头的格式把表格新增一行,而「constructor」的用处是把新增的这一行里面填上数据。我们分三步来看看具体写法。

【第一步:规划field】

在开始「Instantiation」之前,我们要首先确定每一个Object要拥有什么样的信息。比如上面的例子就是一个学生作为Object拥有学号、姓名、年龄、性别四个fields。我们分别使用四个直接依附于Class的变量来存储它们。其中学号(stuID)和年龄(age)各使用一个整数「int」类型的变量存储,而学生姓名(stuName)和性别(gender)则各使用一个「String」类型的字符串变量存储。

public class Main {
	//这里是Main class
	int stuID;
	String stuName;
	int age;
	String gender;
public static void main(String[] agrs) {
		//这里是main method
	}
}

这样,我们就准备好了待会儿需要用到的「field」。但是在上面的这段程序语句中,所有的变量都没有被赋值。相当于表格的表头准备好了,但是还没有添加内容。那么我们就需要用到「constructor」来把内容填入这个表格里。进入第二步。

【第二步:创建constructor】

创建constructor的语句包括三部分:「constructor name」(粉色高亮),「parameter list」(黄色高亮),以及constructor的内容部分(绿色高亮的大括号之间的部分)。其中,「constructor name」必须和它所在的Class的名称保持一致,例如,存在于「Main」 Class里面的constructor就叫「Main」。Parameter list里面可以定义变量,如果必要,这些变量在调用constructor的同时可以存储传进来的待使用的数据,看下面的例子就很好理解。这些被传送到constructor的数据被称为Parameters。如果不需要传送数据,把parameter list留空即可。我们来看具体写法:

因为这个constructor存在于Main class里面,所以constructor name写作Main,与class name 保持一致。而在parameter list 中列有两个parameters,分别是字符串「String f」以及整数变量「int i」。这两个变量在constructor的范围内有效,所以它们只能在绿色高亮的大括号之间也就是这个constructor的范围内被访问到。

注意,我们截止目前只是明确了在调用constructor的时候要接收一个字符串一个整数数据,还没有指明这两个数据的来源就是main method之中的a 和 b。进入第三步,写上指明参数的数据来源的语句。

【第三步:Instantiation】

作为一种特别的method,要启动「constructor」里面的语句的不需要写单独的程序语句来进行调用:一旦某个Class被「instantiate」,「constructor」就会自动被调用。现在,使用 「new」关键词来进行「Instantiation」,这样写:

new Main(a,b);

这就是「Instantiation」的语句,当他被执行时,就创建了一个新的Object,随即调用constructor对object进行初始化。这句话使用了「new」关键词,空格后接着写「constructor name」并用双括号结尾,在这里就是Main()。 这个双括号里则是要传递出去的变量,也就是刚才所说的「参数的数据来源」。此处双括号里面变量的数据类型必须和刚刚建立constructor时parameter list里面声明的变量的数据类型互相兼容,按顺序对齐。比如,刚刚在constructor的parameter list里面我们定义了两个变量,第一个是String类型,第二个是int 类型。那么在「Instantiation」语句中就要先填第一个字符串变量,再写一个逗号用来分隔,最后填入一个整数变量。我们完善上一个例子来更具象的理解:

运行这里第九行的「Instantiation」语句,我们创建了一个object,随即constructor自动被调用。「Instantiation」语句的parameter list按顺序写上了字符串变量 a 以及整数变量 b 。所以main method里面的 a 和 b 变量都在constructor被自动调用的这一瞬间被发送到了 「Main」constructor里面,分别存储在字符串变量 f 和整数变量 i 之中。随后,constructor里面的输出语句访问了 f和 i 两个变量里面存储的数据,得到「看我被传233」的输出结果。这时,constructor的内容执行完毕,程序回到main method第九行后面继续执行,但是第九行后也没有需要执行的语句了,因此程序结束。

【parameters】

逻辑示意图

我们注意到,单个「parameter」在传递前和传递后被分别存储在两个变量中。比如,在main method里面存储233的整数变量是b,但是b 被发送到constructor后就被存储到了变量 i。事实上,这个过程相当于我们复制了一份原来的变量里面存储的数据,然后传送到一个新的容器——也就是使用一个在constructor的parameter list里面新声明的变量——进行存储。这个「原来的变量里面的数据」被称为「Actual parameter」;而新的变量里存储的「复制品」则被称为「Formal parameter」。在数据传递完成后,两个变量相互独立。原来存储「Actual parameter」的变量依然存在,且今后被修改不会影响「Formal parameter」里面的内容。反之亦然。

【举个例子】

我们再回到学生名单的例子来新建一个学生作为object,使用constructor初始化他的四项基本信息:

这个程序就已经完整的展示了从创建field到设置constructor再到「Instantiation」的完整过程。我们在Class中声明了四个变量作为field,并且在constructor里面设置好了要赋给object各项信息的初始值。当主程序开始运行到第11行时,「new Main() 」创建了一个object并同时调用constructor来为这个新建的object 赋初始值。因此现在学号被赋值0002,学生姓名被赋值Goodman,年龄被赋值为51,性别被赋值为F。然后在12-15行,输出语句访问这些数据时,输出了2;Goodman; 51; F。比起前面「看我被传233」的例子,这里的constructor没有parameter,所以parameter list留空;而且,学生名单中「Instantiation」的语句除了右边 new 关键词加上constructor name的部分,还多了左侧「起名」的部分。仔细一想很容易发现,这个格式和声明变量的格式是非常相似的,对比一下:

	Main a = new Main();/instantiation的语句
	int b = 2333;//声明变量的语句

这里「Instantiation」的语句左边部分分别是Class name 和 「代号」。因为是Main class所以此处写的是Main。这个代号类似于变量名,定义变量后可以通过变量名操作变量内的数据,此处则是可以使用代号来对新建的object进行操作。右边部分的格式没有变化,仍然是 new 关键字加上以括号结尾的class name。

U2.3 Calling a Void Method

上文提到的constructor是一种特别的method。我们现在来了解如何创建一个非常普通的void method。我们已经在U2.1了解到,method可以看作是对object进行操作的「功能」。所以我们看下图11-15行创建的method。第11行是对method进行定义,决定这个method有什么性质,叫什么名字等等。void的含义是这个method 没有返回值,我们会在U2.5介绍什么是返回值以及如何写作有返回值的method。现在我们来创建一个method来实现我们想要的功能,在需要使用这个功能的时候调用method就可以运行method里面的语句。比如,如果一个人默认状态下健康码颜色是绿色,现在我们写一个method用于调整健康码颜色为中国红并输出文字提示:

可以看到,我在第七行main method的最开始先进行了实例化「instantiation」的操作,创建了一个代号叫a的object。这个object 有两个field,也就是姓名和健康码颜色,初始值分别为「张三」以及「你码绿的」。直到下面第八行调整颜色的method被调用才会发生颜色的改变,从原来的绿色调整为红色。

因为根据11-14行的代码,这个被用来调整颜色的叫做adjustColor的method里面有两句话,第一句话是调整健康码颜色的数据;第二句话则是输出文字提示,告知用户它现在的健康码颜色并送上祝福。理所当然的,在main method第八行的位置我们调用了改变颜色的method,也就是「call the adjustColor method」来实现健康码颜色的变化。至此,adjustColor method里面的语句被启动,codeColor被重新赋值为「红色哎」,随后的输出语句展示了文字提示。观察一下上方的程序截图最后面的输出结果,在自己的Eclipse 尝试一下复刻这个健康码赋码的程序。

你应该已经发现,method很像一个「黑箱」。我们不用每次都重新写一遍method里面的内容,而是可以反复调用一个被提前写好的method来触发它的功能,从而得到结果。这个过程被称为「Procedural abstraction」

还有一件事,你会发现第8行的调用语句写作「a.adjustColor();」。这个a就是我们给实例起的代号,但是为什么要加个点然后接上method的名字呢?这是因为我们创建的adjustColor是一个「non-static method」,这类method依附于object存在。

所以,我们要使用「dot operator」也就是句点来表示这个被调用的adjustColor method是依附于object a的。这样,整句话最终写作「a.adjustColor();」。意料之中的,相对于「non-static method」就一定有「static method」,这样的method是独立存在的,不依附于object。所以「static method」不需要使用dot operator来表示object和method之间的关联,自然而然的就不需要创建object。

需要注意的是,static methods只能访问static 的数据,所以3-4行声明变量的语句也要加上static关键字。但是,如果一个变量在static method里面被定义,那么不需要单独给这个变量加static关键字,因为存在于static method里面的数据本身就是static的。

U2.4 Calling a Void Method with Parameters

上文的「adjustColor();」以空的括号结尾,这个括号是一个parameter list,留空代表不需要parameter。所以我们刚刚已经学会了如何使用一个没有parameter的method。现在,我们要了解如何创建一个包括参数「parameter」传递功能的method。method的parameter传递和constructor的参数传递的程序语句写法是一模一样的,因为constructor本来就是一种特别的method,你可以回顾U2.2 【第二步】。我们现在来写一个method,用于记录核酸检测的CT值。

public class Main {
	String name;
	int ct;
public static void main(String[] agrs) {
		String temp1 = "张三";//用户输入姓名
		int temp2 = 32;//用户输入ct值
		Main rec = new Main();
		rec.ctRecord(temp2, temp1);//把temp2和temp1里面的数据发送到ctRecord method里
	}

void ctRecord (int v, String n) {//ceRecord method接收发来的数据,存进变量v 和变量 n里
	ct = v;//把变量v收到的用户输入的ct值存入ct变量,作为object的信息之一
	name = n;//同理
	System.out.println(name+"的核酸检测CT值是"+ct);
}
}

我们看到,这次创建ctRecord method的时候括号里的parameter list不再是空白的,而是定义了两个变量等待接收数据,这两个变量是整数变量v 和字符串变量 n。今后调用ctRecord method的时候传进来的数据将分别存储在这两个变量中,这些数据被称为「Formal parameter」。而我们在main method 中调用这个ctRecord method 的时候当然就需要填入用来被发送的数据的变量名,这些被发送的数据也就是参数的来源,被称为「Actual parameter」。一定要记得对于一个参数来说,「Actual parameter」和「Formal parameter」存储在两个独立的变量中。一旦完成传输,「Actual parameter」被改变不会影响「Formal parameter」的内容,反之亦然。下面这张图简单的展示了例子里面带parameter的method的运行逻辑。

蓝色的temp1和temp2变量作为「原数据」,是「Actual parameter」。随后调用了ctRecord method并把temp1和temp2变量里面存储的数据分别复制到了绿色的v 和n 变量里面,作为「Formal parameter」。最后,ctRecord method内部的赋值语句访问了v 和n 变量此时存储的数据,把这些数据分别填入了object的两个fields之内。输出语句运行得到的结果是「张三的核酸检测CT值是32」。

U2.5 Calling a Non-void Method

我们知道void method是指没有返回值的method,因此之前学习的两种method都是单向的,也就是 「调用 -> method运行-> 响应」这样的流程,而不会返回「return」某个数值。但如果我们需要method 运行之后把运算结果「return」,就需要用到non-void method。所谓「return」就是说在non-void method的末尾需要把某一个数值作为运算的结果回传到调用method的语句。所以这个调用method的语句就可以被写为输出表达式的一部分,或者用来给变量赋值。我们举一个加法计算器的例子来理解:

在这个加法计算器中,用户输入两个数并分别存储在main method的变量a 和变量b 里面。第八行我们直接在输出语句的表达式中填写了调用plusCal method的语句。最后输出值为7.33。观察第11行plusCal method里面的语句可以发现,原来的「void」在这里被改写为了「double」,这表示我们要返回的值是一个小数类型的数据。且parameter list中用了两个「double」类型的变量来接收从main method传来的两个小数类型的数据。其后,第12行我们用到了关键字「return」表示method结束,同时返回return后面的数据。这个数据在例子里写作 「h + j」也就是将传来的两个小数相加,这里是2.33+5所以得到结果7.33。至此,plusCal method执行完毕,继续执行第8行的输出语句。我们已经得到7.33作为调用plusCal method的返回值,因此图中深蓝色高亮的调用method的语句可以看作是被7.33替代了。这样的话,最终输出语句访问到的数据是7.33,得到7.33的文字输出。

U2.6 String Objects: Concatenation, Literals, and More

编程可以实现各种各样的功能,有的功能是频繁被用到的。这些频繁被用到的功能就不需要每次都让程序员自己来从头开始写了,一些常用的功能已经被预存在你的电脑里,我们可以直接使用。例如常见的字符串变量String就是通过把很多 char 变量存储的单个字符拼接而成的功能。

public class Main {
public static void main(String[] agrs) {
		String obj = new String();
		obj = "今天是封控的第18天";
		System.out.println(obj);
	}
}

这里的obj就是一个字符串变量,它的Class名就叫String。所以我们在「instantiation」的语句仍然按照惯例写上「<class name> <object name> = new <class name>(); 」这样就得到了一个「String Object」。但是,由于String这个功能真的太过常用了,所以它被进一步简化为:

public class Main {
public static void main(String[] agrs) {
		String obj;
		obj = "今天是封控的第18天";
		System.out.println(obj);
	}
}

省去了「new String();」的部分,更加方便使用。

String object作为一种object,当然也是可以被操作的。我们可以使用「+」或者「+=」这样的符号简单的在一串已有的字符串变量后面扩增新的文本,比如:

我们使用「+」作为连接符,在obj原有的内容后面拼上了新的内容。因此最后得到的输出是「今天是封控的第18天,想鲨人了」。

你还可以使用「 \ 」转译符号来操作字符串里面的文本格式。例如「 \n 」是提行。如果你真的只是想在文本里显示「 \ 」字符显示而不是想把它作为转译符号,就在输出语句表达式里写上「 \\ 」。因为我们需要使用一个转译符号「 \ 」来告诉计算机后面填的第二个「 \ 」是一个字符而不是转译符号。因此「 \\ 」得到的输出显示结果是「 \ 」。一定要区分「 / 」和 「 \ 」,前者只是一个普通字符,任何情况中都会在字符串里面被正常输出。

程序语句中,字符串最开始的「 \\\\ 」被输出显示为「\\」。表达式中「 \\ 」得到输出结果「 \ 」,而例子中两组「 \\ 」得到的输出结果是两个「 \ 」,所以显示为「 \\ 」。其后,「 // 」没有特殊含义只是普通的字符,所以「 // 」正常输出为「 // 」。而「\n」是换行的意思,它让后文从下一行开始显示。现在,在你的eclipse里面尝试输出「 \\\\\n\\\\//\\\\ 」看看会得到什么(不要复制粘贴)。

U2.7 String Methods

我们知道method是用来操作object的。顾名思义String methods就是用来操作string objects的。String methods以及被预设在电脑中,存放在java.lang package里面。「package」是比class还高级的容器,用来存放写好的class。

预设好的String method有查询字符串的文本长度、判断两个文本长度是否相同、输出字符串的其中一截、查询某个字符出现的位置等等功能。

【查询字符串的文本长度】

以String j 为例,在dot operator后使用「length(); 」这个method得到了字符串 j 的长度。返回值为19,表示「Oscar is super good」这一句话包括空格一共有19个字符。

【输出第4到6个字母】

这里用到的method是「substring(); 」,括号里需要填写两个parameter。第一个parameter是输出字符开始的位置,第二个是输出字符结束的位置。字符位置的编号从0开始计算,a的编号是0,所以第四个字母 d的编号是3,第六个字母 f的编号为5。

注意,输出到f需要把结束位置的编号加一,也就是5+1 = 6,这样表示输出到第6位(第7个字母)的字符g为止,并不会输出字符 g。这样得到的输出内容就是「def」了。如果忘记加一,就会导致输出的内容缺少一个字符,得到「de」的结果。注意,在parameter里面输入的字符位置不能小于0,也不能大于这个字符串的最大长度,否则会报「StringIndexOutOfBoundsException」错误。

【查询字母c 第一次出现的位置】

查询字母首次出现的位置使用「indexOf(); 」method,唯一的一个parameter是一个字符串,也就是要被查找的内容。所以这里填上 c 。程序运行后,返回2。因此我们可以在字符串中编号为2的字母 c 。注意,字符串中编号从0 开始计算,第一个字母的编号为0。所以编号为2的字母应该是从左往右数第三个。

【判断两文本内容是否相同】

使用「equals(); 」method,把String j 和括号内parameter的内容对比。例子中的两句话并不完全一致,super 和very 不是相同的字符。因此返回值是 false。如果两个字符串完全相同,则返回true。

【判断两个文本长度是否相同,如果不同长度相差多少】

compareTo(); 」method用来比较 j 字符串和parameter 里面的字符串的长度差距。这里String j 只有三个字符,但是parameter里面的有5个字符。String j 存储的数据比parameter里存储的数据少两个字符,因此返回值为-2。

以上就是考试常用的String methods

U2.8 Wrapper Classes: Integer and Double

「Wrapper class」是把「primitive types」转换为对应的「reference type」。被转换成了「reference types」的变量格式以大写字母开头。比如本来是「primitive types」 的「int」 被转换成「reference type」之后就要写作「Integer」,i从小写 i 变成了大写 I 。double同理,转换后写作「Double」。但是,String本身就是一种「reference type」的变量,因此不能再被转换。

		Integer a = 60;//reference type 
		int b = 60;//primitive type

上面的例子第一行展示的是新建一个reference type 的整数变量;而第二行是primitive type的变量。二者的区别是,reference type 提供了一些预设好的method,比如查询这个数据类型的存储能力:

使用reference type虽然有这些预设的method提供便利,但是对电脑性能的占用更高,程序运算所需的时间也会更长。为了优化程序性能,使用primitive type是一个好办法。

U2.9 Using the Math Class

Math Class也是预设好的功能。我们可以通过Math Class简便的实现计算绝对值、次方、开平方根、以及生成随机数。

在自己的Eclipse里面运行以下代码。注意,程序语句要写在main method里。

【绝对值】

输出 -5的绝对值,得到的结果应该是5。使用「Math.abs()」method,parameter是等待被取绝对值的数。返回值是这个数的绝对值。

		System.out.println(Math.abs(-5));

【次方】

Math.pow()用来计算一个数的次方。parameter list要填入两个数值,第一个是底数,第二个是次幂。这里我们计算2的3次幂,答案为8。输出结果是8.0。

		System.out.println(Math.pow(2,3));

【开平方根】

Math.sqrt()是开平方根的method,在parameter list 里面填上你要开方的数字。这里我们给9开平方根得到3.0作为输出值。

		System.out.println(Math.sqrt(9));

【生成随机数】

生成一个大于等于0,小于1的随机数。不需要填写parameter list。

		System.out.println(Math.random());

总结

第二单元主要讲述了如何创建object并对其进行初始化操作。然后我们介绍了用于在程序中操作object的手段——methods。你可以把一个method看作是一个「功能」,除了自己创建method并通过程序语句编写出自己想要的功能外,你还可以使用别人写好的预设在电脑中的method。

练习

  1. 输入两个数,写四个method实现这两个数的加减乘除。输出它们加减乘除得到的结果。

2.

"AP计算机科学A复习:Unit 2 – Using Objects 面对对象编程", By Liang Haowen
Email contact: [email protected]
No Comments

Send Comment Edit Comment

|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
Previous
Next